{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from collections import Counter"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## kNN算法样例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 8,  8],\n",
       "       [ 3,  7],\n",
       "       [ 7,  0],\n",
       "       [ 4,  2],\n",
       "       [ 5,  2],\n",
       "       [12, 12],\n",
       "       [11, 10],\n",
       "       [18, 14],\n",
       "       [10, 19],\n",
       "       [16, 12]])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.random.seed(100) # 生成随机数种子\n",
    "x1 = np.random.randint(0,10,size=10).reshape(-1,2) # 生成第一类数据\n",
    "x2 = np.random.randint(10,20,size=10).reshape(-1,2) # 生成第二类数据\n",
    "X = np.concatenate((x1,x2),axis=0) # 合并两类数据\n",
    "X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(10,)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = np.array([0,0,0,0,0,1,1,1,1,1]) # X数据的分类标签\n",
    "y.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "x_p = np.array([[10,10]]) # 生成待预测数据\n",
    "plt.scatter(x1[:,0],x1[:,1],color='r') # 绘图第一类数据\n",
    "plt.scatter(x2[:,0],x2[:,1],color='g') # 绘图第二类数据\n",
    "plt.scatter(x_p[:,0],x_p[:,1],color='b') # 绘图待预测数据\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "distances = [np.sum(np.abs(x_p-item)**2)**(1/2) for item in X] # 欧拉距离计算相似度\n",
    "nearest = np.argsort(distances)[:3] # 选取最近的3个点\n",
    "y_label = y[nearest] # 最近3个点的分类标签\n",
    "Counter(y_label).most_common(1)[0][0] # 统计分类标签最多的，待预测数据即属于该分类标签"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 封装kNN算法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def kNN_classify(X_train, y_train, x_predict, k=5, p=2):\n",
    "    '''kNN分类器'''\n",
    "    assert k >0, 'k需要大于0'\n",
    "    assert k <= y_train.shape[0], 'k不能大于总样本数'\n",
    "    assert p > 0, 'p需要大于0'\n",
    "    assert X_train.shape[1] == x_predict.shape[1], '预测数据特征数量需要等于样本的特征数量'\n",
    "    assert X_train.shape[0] == y_train.shape[0], '训练数据样本数量需要等于训练分类数量'\n",
    "    \n",
    "    return np.array([_predict(X_train, y_train, x, k, p) for x in x_predict])\n",
    "\n",
    "def _predict(X_train, y_train, x, k, p):\n",
    "    '''预测函数'''\n",
    "    distances = [distance(item, x, p) for item in X_train]\n",
    "    nearest = np.argsort(distances)[:k]\n",
    "    k_labels = y_train[nearest]\n",
    "    return Counter(k_labels).most_common(1)[0][0]\n",
    "\n",
    "def distance(a, b, p=2):\n",
    "    '''计算明可夫斯基距离'''\n",
    "    return np.sum(np.abs(a - b) ** p) ** (1 / p)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "kNN_classify(X, y, x_p, k=3) # 调用kNN_classify函数,结果与之前一致"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([7, 6, 1, 5, 4, 2, 0, 3, 9, 8])"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'''测试随机排列'''\n",
    "np.random.seed(100)\n",
    "np.random.permutation(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 留出法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train_test_split(X, y, test_size=0.25, seed=None):\n",
    "    '''hold-out'''\n",
    "    assert X.shape[0] == y.shape[0], \"X中样本数量需要等于y中的标签数量\"\n",
    "\n",
    "    assert 0 <= test_size <= 1, \"test_size有效范围为0到1之间\"\n",
    "\n",
    "    if seed:\n",
    "        np.random.seed(seed)\n",
    "\n",
    "    shuffle = np.random.permutation(len(X))\n",
    "\n",
    "    size = int(len(X) * test_size)\n",
    "\n",
    "    test_index = shuffle[:size]\n",
    "    train_index = shuffle[size:]\n",
    "\n",
    "    X_train = X[train_index]\n",
    "    y_train = y[train_index]\n",
    "\n",
    "    X_test = X[test_index]\n",
    "    y_test = y[test_index]\n",
    "\n",
    "    return X_train, X_test, y_train, y_test"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据标准化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "class StandardScaler:\n",
    "    '''standardization'''\n",
    "    def __init__(self):\n",
    "        self.mean_ = None  # 均值\n",
    "        self.scale_ = None # 标准差\n",
    "\n",
    "    def fit(self, X):\n",
    "\n",
    "        self.mean_ = np.mean(X, axis=0)\n",
    "        self.scale_ = np.std(X, axis=0)\n",
    "\n",
    "        return self\n",
    "\n",
    "    def transform(self, X):\n",
    "\n",
    "        assert self.mean_ is not None and self.scale_ is not None, \\\n",
    "            '请先调用fit方法'\n",
    "\n",
    "        assert X.shape[1] == len(self.mean_), \\\n",
    "            'X的特征数量需要与fit时传入的数据相同'\n",
    "\n",
    "        temp = np.empty(shape=X.shape, dtype=float)\n",
    "\n",
    "        for col in range(X.shape[1]):\n",
    "            temp[:, col] = (X[:, col] - self.mean_[col]) / self.scale_[col]\n",
    "\n",
    "        return temp"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 准确率计算"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "def accuracy_score(y, y_predict):\n",
    "    '''计算准确率'''\n",
    "\n",
    "    assert y.shape[0] == y_predict.shape[0], \\\n",
    "        'y与y_predict长度需要相同'\n",
    "\n",
    "    return sum(y == y_predict) / len(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 实战-鸢尾花分类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(150, 4)"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "df = pd.read_table(r'D:\\csdn-python\\第十六周 数据挖掘与机器学习进阶（上）\\05-发给学员\\data\\iris\\x.txt', engine='python', header=None, sep=' ')\n",
    "X_train = df.values\n",
    "X_train.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(150,)"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = pd.read_table(r'D:\\csdn-python\\第十六周 数据挖掘与机器学习进阶（上）\\05-发给学员\\data\\iris\\y.txt', engine='python', header=None, sep=' ')\n",
    "y_train=y.values[:,-1]\n",
    "y_train.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.scatter(X_train[y_train==0,2],X_train[y_train==0,3],color='r') # 绘图第一类数据\n",
    "plt.scatter(X_train[y_train==1,2],X_train[y_train==1,3],color='g') # 绘图第二类数据\n",
    "plt.scatter(X_train[y_train==2,2],X_train[y_train==2,3],color='b') # 绘图第三类数据\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "standard = StandardScaler()\n",
    "standard.fit(X_train)\n",
    "X2 = standard.transform(X_train)\n",
    "plt.scatter(X2[y_train==0,2],X2[y_train==0,3],color='r') # 绘图第一类数据\n",
    "plt.scatter(X2[y_train==1,2],X2[y_train==1,3],color='g') # 绘图第二类数据\n",
    "plt.scatter(X2[y_train==2,2],X2[y_train==2,3],color='b') # 绘图第三类数据\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.972972972972973"
      ]
     },
     "execution_count": 86,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X2_train, X2_test, y2_train, y2_test = train_test_split(X2, y_train, test_size=0.25, seed=100)\n",
    "y_predict = kNN_classify(X2_train, y2_train, X2_test)\n",
    "accuracy_score(y2_test,y_predict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.972972972972973"
      ]
     },
     "execution_count": 87,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X2_train, X2_test, y2_train, y2_test = train_test_split(X_train, y_train, test_size=0.25, seed=100)\n",
    "y_predict = kNN_classify(X2_train, y2_train, X2_test)\n",
    "accuracy_score(y2_test,y_predict)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 网格搜索模型参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "best_k 7\n",
      "best_p 2\n",
      "best_score 1.0\n"
     ]
    }
   ],
   "source": [
    "best_score = 0\n",
    "best_k = 0\n",
    "best_p = 0\n",
    "for k in range(1, 21):\n",
    "    for p in range(1, 10):\n",
    "        y_predict = kNN_classify(X2_train, y2_train, X2_test, k=k, p=p)\n",
    "        score = accuracy_score(y2_test, y_predict)\n",
    "        if score > best_score:\n",
    "            best_score = score\n",
    "            best_k = k\n",
    "            best_p = p\n",
    "            \n",
    "print('best_k', best_k)\n",
    "print('best_p', best_p)\n",
    "print('best_score', best_score)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "celltoolbar": "Raw Cell Format",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
